package com.kly.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kly.common.ErrorCode;
import com.kly.common.UserContext;
import com.kly.constant.UserConstant;
import com.kly.enums.TeamStatus;
import com.kly.exception.BusinessException;
import com.kly.mapper.TeamMapper;
import com.kly.mapper.UserMapper;
import com.kly.model.domain.Team;
import com.kly.model.domain.User;
import com.kly.model.domain.UserTeam;
import com.kly.model.dto.JoinTeamDto;
import com.kly.model.dto.TeamDto;
import com.kly.model.dto.TeamQuery;
import com.kly.model.vo.PageResult;
import com.kly.model.vo.TeamVo;
import com.kly.model.vo.UserVo;
import com.kly.service.TeamService;
import com.kly.service.UserTeamService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author admin
 * @description 针对表【team(队伍表)】的数据库操作Service实现
 * @createDate 2025-02-23 21:58:40
 */
@RequiredArgsConstructor
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService {

    private final UserTeamService userTeamService;

    private final UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createTeam(TeamDto teamDto) {
        verifyTeamInfo(teamDto);
        // 一个用户最多创建5个队伍
        // 线程安全 synchronized
        User user = UserContext.getUser();
        Long userId = user.getId();
        if (userId == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN, "用户未登录");
        }
        synchronized (userId.toString().intern()) {
            Long count = this.lambdaQuery()
                    .eq(Team::getUserId, userId)
                    .count();
            if (count >= 5) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多创建5个队伍");
            }

            // 插入队伍信息
            Team team = new Team();
            BeanUtils.copyProperties(teamDto, team, "id");
            team.setUserId(userId);

            if(team.getImage() == null) {
                team.setImage("https://tse2-mm.cn.bing.net/th/id/OIP-C.yMAeC3o1ZnVZYsQecLSlEAAAAA?rs=1&pid=ImgDetMain");
            }
            Date expireTime = new Date(2026, Calendar.FEBRUARY, 1);
            team.setExpireTime(expireTime);

            boolean save = this.save(team);
            if (!save) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR);
            }

            // 插入用户队伍关系
            Long teamId = team.getId();
            if (teamId == null) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR);
            }

            UserTeam userTeam = UserTeam.builder()
                    .userId(userId)
                    .teamId(teamId)
                    .joinTime(new Date())
                    .build();
            boolean save1 = userTeamService.save(userTeam);
            if (!save1) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR);
            }
            return teamId;
        }
    }

    private static void verifyTeamInfo(TeamDto teamDto) {
        if (teamDto == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //     队伍人数1-20
        Integer maxNum = teamDto.getMaxNum();
        if (maxNum == null || maxNum < 1 || maxNum > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不满足要求");
        }
        //     队伍标题字数小于20
        String name = teamDto.getName();
        if (StringUtils.isBlank(name) || name.length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不满足要求");
        }
        //     队伍描述字数小于512
        String description = teamDto.getDescription();
        if (StringUtils.isBlank(description) || description.length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述不满足要求");
        }

        // status 0 公开 1 私有 2 加密
        int status = Optional.ofNullable(teamDto.getStatus()).orElse(0);
        TeamStatus enumByCode = TeamStatus.getEnumByCode(status);
        if (enumByCode == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求");
        }
        // 如果是加密队伍，需要密码 小于32位
        if (TeamStatus.ENCRYPTED.equals(enumByCode)) {
            String password = teamDto.getPassword();
            if (StringUtils.isBlank(password) || password.length() > 32) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍密码不满足要求");
            }
        }
        // 判断是否超时
        Date date = new Date();
        Date expireTime = new Date(2026, 1, 1);
        if (expireTime != null && expireTime.before(date)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍过期时间不满足要求");
        }
    }

    @Override
    public PageResult<TeamVo> searchTeamsByPage(TeamQuery teamQuery, Boolean type) {
        if (teamQuery == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 搜索关键词
        String searchText = teamQuery.getSearchText();

        String name = teamQuery.getName();
        String description = teamQuery.getDescription();
        Integer maxNum = teamQuery.getMaxNum();
        Date expireTime = teamQuery.getExpireTime();
        Integer status = teamQuery.getStatus();

        List<Long> teamIdList = teamQuery.getTeamIdList();

        // 当前时间
        Date date = new Date();
        Long userId = teamQuery.getUserId();
        // Integer status = Optional.ofNullable(teamQuery.getStatus()).orElse(TeamStatus.PUBLIC.getCode());

        // 获取登录用户信息
        User user = UserContext.getUser();
        if (user == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN, "用户未登录");
        }
        Integer role = user.getRole();

        Page<Team> page = this.lambdaQuery()
                .like(StringUtils.isNotBlank(name), Team::getName, name)
                .like(StringUtils.isNotBlank(description), Team::getDescription, description)
                .eq(maxNum != null, Team::getMaxNum, maxNum)
                .eq(userId != null, Team::getUserId, userId)
                .lt(expireTime != null, Team::getExpireTime, expireTime)
                .eq(status != null, Team::getStatus, status)
                .in(teamIdList != null, Team::getId, teamIdList)
                // 过期的队伍不展示
                .gt(Team::getExpireTime, date)
                // 关键词查询
                .and(StringUtils.isNotBlank(searchText),
                        qw -> qw.like(Team::getName, searchText)
                                .or()
                                .like(Team::getDescription, searchText)
                )
                .page(new Page<>(teamQuery.getPageNo(), teamQuery.getPageSize()));

        List<Team> records = page.getRecords();
        // 如果是普通用户，只返回公开队伍和加密队伍
        if(type) {
            if (UserConstant.COMMON_ROLE.equals(role)) {
                records = records.stream()
                        .filter(team -> TeamStatus.PUBLIC.equals(TeamStatus.getEnumByCode(team.getStatus()))
                                || TeamStatus.ENCRYPTED.equals(TeamStatus.getEnumByCode(team.getStatus())))
                        .collect(Collectors.toList());
            }
        }

        List<TeamVo> teamVoList = BeanUtil.copyToList(records, TeamVo.class);
        // 查询已加入用户信息
        teamVoList.forEach(teamVo -> {
            Long teamId = teamVo.getId();
            List<UserVo> userVoList = userMapper.selectUsersByTeamId(teamId);
            teamVo.setUserList(userVoList);
        });


        return PageResult.<TeamVo>builder()
                .records(teamVoList)
                .total(page.getTotal())
                .build();
    }

    @Override
    public Boolean updateTeam(TeamDto teamDto) {
        verifyTeamInfo(teamDto);
        // 判断队伍状态是否合法 加密队伍 密码不为空
        // 公开队伍 密码为空
        Integer status = teamDto.getStatus();
        if (TeamStatus.ENCRYPTED.getCode().equals(status)) {
            String password = teamDto.getPassword();
            if (StringUtils.isBlank(password)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码不能为空");
            }
        } else if (TeamStatus.PUBLIC.getCode().equals(status)) {
            String password = teamDto.getPassword();
            if (StringUtils.isNotBlank(password)) {
                teamDto.setPassword(null);
            }
        }

        // 查询数据库表
        Long id = teamDto.getId();
        Team teamDb = this.getById(id);
        if (teamDb == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }

        teamDto.setUserId(teamDb.getUserId());


        // 队长和管理员可以修改队伍信息
        User user = UserContext.getUser();
        Integer role = user.getRole();
        Long userId = user.getId();
        if (!UserConstant.ADMIN_ROLE.equals(role) && !teamDto.getUserId().equals(userId)) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }


        Team team = new Team();
        BeanUtils.copyProperties(teamDto, team);


        // TODO 修改expireTime
        team.setExpireTime(new Date(2026,2,1));

        // 更新
        return this.updateById(team);
    }

    @Override
    public Boolean joinTeam(JoinTeamDto joinTeamDto) {
        if (joinTeamDto == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = joinTeamDto.getTeamId();
        // userId为空 默认为当前用户
        Long userId = Optional.ofNullable(joinTeamDto.getUserId())
                .orElse(UserContext.getUser().getId());

        synchronized(userId.toString().intern()) {
            // 查询队伍人数
            Long peopleNum = userTeamService.lambdaQuery()
                    .eq(UserTeam::getTeamId, teamId)
                    .count();

            // 队伍存在 且人数未满，未过期


            Team team = lambdaQuery().eq(Team::getId, teamId)
                    .gt(Team::getExpireTime, new Date())
                    .gt(Team::getMaxNum, peopleNum)
                    .one();
            if (team == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在或已满");
            }


            // 用户最多 加入 5 个队伍
            Long count = userTeamService.lambdaQuery()
                    .eq(UserTeam::getUserId, userId).count();
            if (count >= 5) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多加入5个队伍");
            }

            // 不能加入自己的队伍
            if (team.getUserId().equals(userId)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能加入自己的队伍");
            }

            // * 不能加入已加入的队伍
            UserTeam one = userTeamService.lambdaQuery()
                    .eq(UserTeam::getUserId, userId)
                    .eq(UserTeam::getTeamId, teamId)
                    .one();
            if (one != null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能重复加入同一队伍");
            }

            // 不能加入私有队伍
            if (TeamStatus.PRIVATE.getCode().equals(team.getStatus())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能加入私有队伍");
            }

            // 加密队伍 密码匹配
            if (TeamStatus.ENCRYPTED.getCode().equals(team.getStatus())) {
                String password = joinTeamDto.getPassword();
                if (StringUtils.isBlank(password) || !team.getPassword().equals(password)) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
                }
            }

            // 关联用户队伍表
            UserTeam userTeam = UserTeam.builder()
                    .userId(userId)
                    .teamId(teamId)
                    .joinTime(new Date())
                    .build();

            return userTeamService.save(userTeam);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean quitTeam(JoinTeamDto joinTeamDto) {
        if (joinTeamDto == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = joinTeamDto.getTeamId();
        Long userId = Optional.ofNullable(joinTeamDto.getUserId())
                .orElse(UserContext.getUser().getId());
        if (teamId == null || userId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 查找team
        Team teamDb = lambdaQuery().eq(Team::getId, teamId).one();
        if (teamDb == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }

        // 查看是否是成员
        UserTeam userTeamDb = userTeamService.lambdaQuery()
                .eq(UserTeam::getUserId, userId)
                .eq(UserTeam::getTeamId, teamId)
                .one();
        if (userTeamDb == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "未加入队伍");
        }

        //      判断队伍人数
        Long peopleNum = userTeamService.lambdaQuery()
                .eq(UserTeam::getTeamId, teamId)
                .count();


        // 判断是否是队长
        if (teamDb.getUserId().equals(userId) && peopleNum > 1) {

            //     查看下一个成员
            UserTeam one = userTeamService.lambdaQuery()
                    .eq(UserTeam::getTeamId, teamId)
                    .gt(UserTeam::getJoinTime, userTeamDb.getJoinTime())
                    .orderByAsc(UserTeam::getJoinTime)
                    .last("limit 1").one();
            //     转移队长权限
            this.lambdaUpdate()
                    .eq(Team::getId, teamId)
                    .set(Team::getUserId, one.getUserId())
                    .update();

        }

        if (peopleNum == 1) {
            //     解散队伍
            this.lambdaUpdate()
                    .eq(Team::getId, teamId)
                    .remove();
        }

        return userTeamService.lambdaUpdate()
                .eq(UserTeam::getTeamId, teamId)
                .eq(UserTeam::getUserId, userId)
                .remove();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteTeam(Long teamId) {
        if (teamId == null || teamId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 判断队伍是否存在
        Team teamDb = this.getById(teamId);
        if (teamDb == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 判断是否是队长
        User user = UserContext.getUser();
        if (user == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        Integer role = user.getRole();
        Long userId = user.getId();

        // 只有管理员和队长可以删除队伍
        if (!userId.equals(teamDb.getUserId()) && !role.equals(UserConstant.ADMIN_ROLE)) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }

        // 删除用户队伍关系
        userTeamService.lambdaUpdate()
                .eq(UserTeam::getTeamId, teamId)
                .remove();

        // 删除队伍
        return this.removeById(teamId);
    }

}




